﻿// dotnet5="../../Backend" ; dotnet $DOTNET_CSC_DLL -nologo -t:library -r:"$dotnet5/System.dll" -r:"$dotnet5/System.Core.dll" -r:"$dotnet5/System.Text.Json.dll" -r:"$dotnet5/System.Collections.dll" -r:"$dotnet5/mscorlib.dll" -r:"$dotnet5/netstandard.dll" -r:"../../Backend/GameData.dll" -r:"../../The Scroll of Taiwu_Data/Managed/TaiwuModdingLib.dll" -r:"$dotnet5/System.Private.CoreLib.dll" -r:"$dotnet5/System.IO.MemoryMappedFiles.dll" -r:"$dotnet5/System.Runtime.dll" -r:"$dotnet5/System.Runtime.InteropServices.dll" -r:"$dotnet5/System.Linq.dll" -r:"$dotnet5/System.Text.Encodings.Web.dll" -r:"$dotnet5/System.IO.FileSystem.dll" -unsafe -optimize -deterministic -debug Backend.cs *.CS -out:Backend.dll -debug -define:BACKEND -nowarn:CS1702 # -define:SPEEDTEST -define:Json
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Text.Json;

using GameData.Common;
using GameData.Domains;
using GameData.Domains.Character;
using GameData.Domains.Map;
using GameData.GameDataBridge;
using GameData.Utilities;
using System.Collections.Generic;
using System.IO.MemoryMappedFiles;
using TaiwuModdingLib.Core.Plugin;
using static NpcScan.Const;
using static Utils.Logger;
namespace NpcScan
{
    [PluginConfig("NPCScanBckend", "Neutron3529, 发射的熟鸡蛋", "0.2")]
    public class Backend : TaiwuRemakePlugin
    {
        public override void Initialize(){}
        public override void Dispose(){
            if (memoryMappedFile != null)
            {
                memoryMappedFile.Dispose();
                memoryMappedFile = null;
            }
        }
        public override void OnLoadedArchiveData()
        {
            base.OnLoadedArchiveData();
            this.Dispose();
        }

        private static MemoryMappedFile memoryMappedFile;
        public static readonly FieldInfo _AliveCharacter=typeof(GameData.Domains.Character.CharacterDomain).GetField("_objects",(BindingFlags)(-1));
        public static readonly FieldInfo _DeadCharacter=typeof(GameData.Domains.Character.CharacterDomain).GetField("_deadCharacters",(BindingFlags)(-1));
        public static readonly FieldInfo _Grave=typeof(GameData.Domains.Character.CharacterDomain).GetField("_graves",(BindingFlags)(-1));
        public static int taiwuCharId=-1;
        public static readonly JsonSerializerOptions options = new JsonSerializerOptions(){IncludeFields = true, Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping};
        public unsafe int GetCharactersData(Operation operation, RawDataPool argDataPool, RawDataPool returnDataPool, DataContext context) {
            Dictionary<int, Character> AliveCharacterDic = (Dictionary<int, Character>)_AliveCharacter.GetValue(DomainManager.Character);
            Dictionary<int, DeadCharacter> DeadCharacterDic = (Dictionary<int, DeadCharacter>)_DeadCharacter.GetValue(DomainManager.Character);
            Dictionary<int, Grave> GraveDic = (Dictionary<int, Grave>)_Grave.GetValue(DomainManager.Character);
            List<CharacterData> characterDataList = new List<CharacterData>(AliveCharacterDic.Count + DeadCharacterDic.Count);
            NMdict.Clear();
            taiwuCharId=DomainManager.Taiwu.GetTaiwuCharId();
            foreach (var character in AliveCharacterDic.Values)
            {
                var c=character.GetCreatingType();
                if (c != 2 && c != 3) {
                    CharacterData characterData = new CharacterData();
                    characterData.SetData(character);
                    characterDataList.Add(characterData);
                    // if(characterDataList.Count==0)logwarn($"{characterDataList[0].id}, {characterDataList[0].gender}, characterData.id, characterData.gender");
                }
            }
            // logwarn($"{characterDataList[0].id}, {characterDataList[0].gender}");
            #if SPEEDTEST
            System.Diagnostics.Stopwatch w=System.Diagnostics.Stopwatch.StartNew();
            #endif
            foreach (var (id, character) in DeadCharacterDic)
            {
                CharacterData characterData = new CharacterData();
                List<GameData.Domains.Item.ItemKey> itmlst=null;
                Grave grave=null;
                Location location=new Location(-1,-1);
                if(GraveDic.TryGetValue(id,out grave)){
                    location=grave.GetLocation();
                    itmlst = grave.GetInventory().Items.Keys.ToList() ;
                }

                characterData.SetDeadData(id, character, GraveDic.ContainsKey(id) ? GraveDic[id].GetLocation() : new Location(-1, -1), itmlst);

                characterDataList.Add(characterData);
            }
            #if SPEEDTEST
            w.Stop();
            logwarn($"collect cost {w.ElapsedMilliseconds}");
            w.Restart();
            #endif

            #if Json
            // // logwarn($"{characterDataList[0].id}, {characterDataList[0].gender}");
            // // string jsonContent = JsonSerializer.Serialize(characterDataList, options);
            // // byte[] data = Encoding.Unicode.GetBytes(jsonContent);
            //
            // byte[] data = JsonSerializer.SerializeToUtf8Bytes(characterDataList, options);
            //
            // #if SPEEDTEST
            // w.Stop();
            // logwarn($"JsonSerializer cost {w.ElapsedMilliseconds}");
            // w.Restart();
            // #endif
            // if (memoryMappedFile != null)
            //     memoryMappedFile.Dispose();
            // memoryMappedFile = MemoryMappedFile.CreateOrOpen("NpcScanData", data.LongLength);
            //
            // #if SPEEDTEST
            // w.Stop();
            // logwarn($"OpenMem cost {w.ElapsedMilliseconds}");
            // w.Restart();
            // #endif
            // using (var accessor = memoryMappedFile.CreateViewAccessor())
            // {
            //     accessor.WriteArray(0, data, 0, data.Length);
            // }
            //
            // var total=(from d in characterDataList select d.size()).Sum()+4;
            // byte[]arr=new byte[total];
            // fixed(byte*ptr=arr){
            //     *(int*)ptr=characterDataList.Count;
            //     var ptr2=ptr+4;
            //     foreach(var d in characterDataList){
            //         var ptr3=d.Ser(ptr2);
            //         logger($"id={d.id};ptrdiff={(int)ptr3-(int)ptr2},len={d.size()},ptrnext={(int)ptr3-(int)ptr}");
            //         if(d.size()!=(int)ptr3-(int)ptr2){
            //             logwarn("mismatch: id={d.id};ptrdiff={(int)ptr3-(int)ptr2},len={d.size()},ptrnext={(int)ptr3-(int)ptr}");
            //         }
            //         ptr2=ptr3;
            //     }
            // }

            #else



            var total=(from d in characterDataList select d.size()).Sum()+4;

            #if SPEEDTEST
            w.Stop();
            logwarn($"calc len cost {w.ElapsedMilliseconds}");
            w.Restart();
            #endif
            byte[]arr=new byte[total];
            fixed(byte*ptr=arr){
                *(int*)ptr=characterDataList.Count;
                var ptr2=ptr+4;
                foreach(var d in characterDataList){
                    var ptr3=d.Ser(ptr2);
                    // logger($"id={d.id};ptrdiff={(int)ptr3-(int)ptr2},len={d.size()},ptrnext={(int)ptr3-(int)ptr}");
                    // if(d.size()>1000){
                    //     logwarn($"here we got:size={d.size()},expr={168+d.featureIds.Length*2+d.potentialFeatureIds.Length*2+d.samsara.Length*4+d.items.Length*4+3},detail is 168+{d.featureIds.Length}*2+{d.potentialFeatureIds.Length}*2+{d.samsara.Length}*4+{d.items.Length}*4+3");
                    // }
                    // if(d.size()!=(int)ptr3-(int)ptr2){
                    //     logwarn($"mismatch: id={d.id};ptrdiff={(int)ptr3-(int)ptr2},len={d.size()},ptrnext={(int)ptr3-(int)ptr}");
                    // }
                    ptr2=ptr3;
                }
                // logger($"ptrnext={(int)ptr2-(int)ptr},total={total}");
            }

            #if SPEEDTEST
            w.Stop();
            logwarn($"prepare data cost {w.ElapsedMilliseconds}");
            w.Restart();
            #endif

            if (memoryMappedFile != null)
                memoryMappedFile.Dispose();
            memoryMappedFile = MemoryMappedFile.CreateOrOpen("NpcScanData", arr.LongLength);
            using (var accessor = memoryMappedFile.CreateViewAccessor()) {
                accessor.WriteArray(0, arr, 0, arr.Length);
            }

            #endif

            #if SPEEDTEST
            w.Stop();
            logwarn($"WriteMem cost {w.ElapsedMilliseconds}");
            #endif
            // logwarn($"后端发送{characterDataList.Count}个数据，长度为{data.Length}");

            return GameData.Serializer.Serializer.Serialize(NMdict, returnDataPool);
        }
    }
}
